package nape.shape;
import nape.shape.Polygon;
import nape.shape.Shape;
import nape.geom.AABB;
import nape.geom.Axis;
import nape.geom.Mat23;
import nape.geom.Vec2;
import nape.geom.VecMath;
import nape.util.FastMath;
import nape.util.MixPool;
import nape.util.Names;
import nape.util.NpAlgorithm;
import nape.util.NpList;
import nape.phys.Material;
import nape.Config;
import nape.Const;
import nape.util.NpNode_ZNContact;
import nape.util.NpAllocList_ZNContact;
import nape.util.NpNode_ZNV2;
import nape.util.NpList_ZNV2;
import nape.util.NpNode_Vec2__Dynamic;
import nape.util.NpList_Vec2__Dynamic;
import nape.util.NpNode_ZNShp;
import nape.util.NpList_ZNShp;












class Circle extends Shape {
    public var znp_inner:ZNCirc;
    
    
    
    
    public function new(radius:Float, ?localCOM:Vec2, ?material:Material) {
        if(radius<Const.EPSILON) radius = 10.0;
        if(material==null) material = Config.DEFAULT_MATERIAL;
        znp_inner = new ZNCirc(radius, localCOM, material.znp_inner);
        znp_inner.outer = this;
        
        znp_inner.outer_shape = this;
        znp_inner_shape = znp_inner;
    }
    
    
    
    public var radius(get_radius,set_radius):Float;
    
    public inline function get_radius() return znp_inner.radius
    
    public inline function set_radius(radius:Float) {
        if(radius>Const.EPSILON && this.radius!=radius) {
            znp_inner.radius = radius;
            znp_inner.invalidate_radius();
        }
        return this.radius;
    }
    
    
    
    public override function toString() {
        return "Circle #"+id;
    }
}



class ZNCirc extends ZNShp {
    public var outer:Circle;
    
    
    
    public var radius:Float;
    public var rollingFriction:Bool;
    
    
    
    
    public function new(radius:Float, localCOM:Vec2, material:ZNMat) {
        super(Shape.CIRCLE,material);
        circle = this;
        
        if(localCOM==null)  { this.localCOMx = 0; this.localCOMy = 0; };
        else     { this.localCOMx = localCOM.znp_inner.x; this.localCOMy = localCOM.znp_inner.y; };
        
        this.radius = radius;
        rollingFriction = false;
        
         _inv_localCOM = false;
    }
    
    
    
    
    public function setLocalCOM(x:Vec2) {
            { localCOMx = x.znp_inner.x; localCOMy = x.znp_inner.y; };
        invalidate_localCOM();
    }
    
    
    
    public inline function invalidate_radius() {
        invalidate_area_inertia();
        invalidate_angDrag();
    }
    
    
    
    
    public inline function __validate_area_inertia() {
        var r2 = radius*radius;
        area = r2*Math.PI;
        inertia = r2*.5 +     (localCOMx*localCOMx + localCOMy*localCOMy);
    }
    
    public inline function __validate_angDrag() {
        
        
		var skin_f = material.dynamicFriction*Config.ANGDRAGCOEF_FRICTION;
		var ratio2 =     (localCOMx*localCOMx + localCOMy*localCOMy)/(radius*radius);
		angDrag = skin_f*(1.0 + 0.5*ratio2)/Math.PI;
    }
    
    
    
    public inline function __scale(factor:Float) {
        radius *= factor < 0 ? -factor : factor;
        invalidate_radius();
        
        if(    (localCOMx*localCOMx + localCOMy*localCOMy)>0) {
             { var t = (factor); localCOMx *= t; localCOMy *= t; };
            invalidate_localCOM();
        }
    }
    
    public inline function __translate(x:Float,y:Float) {
          { var t = (1.0); localCOMx += x*t; localCOMy += y*t; };
        invalidate_localCOM();
    }
    
    public inline function __rotate(x:Float,y:Float) {
        if(    (localCOMx*localCOMx + localCOMy*localCOMy)>0) {
                   var tx:Float;  var ty:Float;
             { tx =  (localCOMy*x - localCOMx*y); ty =  (localCOMx*x + localCOMy*y); };
                { localCOMx = tx; localCOMy = ty; };

            invalidate_localCOM();
        }
    }
    
    public inline function __transform(m:Mat23) {
        var det =  (m.a*m.d - m.b*m.c); if(det<0) det = -det;
        radius *= Math.sqrt(det);
        
         {
    var t = m.a*localCOMx + m.b*localCOMy;
    localCOMy   = m.c*localCOMx + m.d*localCOMy;
    localCOMx   = t;
};
          { var t = (1.0); localCOMx += m.tx*t; localCOMy += m.ty*t; };

        invalidate_radius();
        invalidate_localCOM();
    }
}
